﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using DG.Tweening;
using TKC.Scripts.Core.Component;
using TKC.Scripts.Core.Utils;
using UnityEngine;
using UnityEngine.Serialization;

namespace TKC.Scripts.Components.CameraGesture
{
    public delegate bool EventCheckDelegate();
    public delegate void PointerDelegate(Vector2 screenPos, Vector3 worldPos);
    public delegate bool PointerDragDelegate(Vector2 screenPos);
    public delegate void PointerZoomDelegate(int screenZoom );

    public class CameraGesture : MonoSingleton<CameraGesture>, IInput
    {
        static private bool _IsCameraOn_proxy() { return true; }
        static private bool _OnDrag_proxy(Vector2 screenPos) { return false; }
        static private void _Pointer_proxy(Vector2 screenPos, Vector3 worldPos) { }
        static private void _Zoom_proxy(int Zoom ) { }
        
        public EventCheckDelegate IsCameraOn = _IsCameraOn_proxy;
        public PointerDelegate OnPointDown = _Pointer_proxy;
        public PointerDelegate OnPointUp = _Pointer_proxy;
        public PointerDelegate OnTap = _Pointer_proxy;
        public PointerZoomDelegate OnZoom = _Zoom_proxy;
        public PointerDragDelegate OnDrag = _OnDrag_proxy;

        public static Vector3 nullPointer = new Vector3(-99999, -99999, -99999);
        // *********************************
        public int MaxZoomLevel = 7;
        public float mMaxHeight = 12;
        public float mMinHeight = 5;
        public Camera mCamera = null;
        //
        private Transform _cameraTransform;
        private Ray _ray;
        private RaycastHit _rayHit;
        private Vector3 _pointerDown = nullPointer;
        private float _perLevelHeight = 0;
        private float _zoomFactor = 10;
        private float _lastPointerTime = 0;
        private float _factor = 1;
        private int _curZoom = 2;
        private int _lastZoom = 2;
        bool _cameraOn = true;
        private bool _CameraFonze = false;
        private bool _zooming = false;   
        bool _zoomEffecting = false;

        private IInputProvider _inputProvider;

        public int ZoomLevel
        {
            get
            {
                return _curZoom;
            }
        }

        protected override void Awake()
        {
            base.Awake();
#if UNITY_EDITOR || UNITY_STANDALONE
            _inputProvider = new MouseProvider(this);
#else
            _inputProvider = new TouchProvider(this);
#endif
            if (!mCamera)
                mCamera = gameObject.GetComponent<Camera>();
            _cameraTransform = mCamera.transform;

            _perLevelHeight = (mMaxHeight - mMinHeight) * 1.0f / MaxZoomLevel;
        }
        public void Enter()
        {
            mCamera.enabled = true;
            _zooming = false;
            UpdateShadowDistance();
            UpdateMoveSpeedFactor();
        }
        public void Exit()
        {
            mCamera.enabled = false;
            _zooming = false;
            //reset all deletage
            IsCameraOn = _IsCameraOn_proxy;
            OnPointDown = _Pointer_proxy;
            OnPointUp = _Pointer_proxy;
            OnTap = _Pointer_proxy;
            OnZoom = _Zoom_proxy;
            OnDrag = _OnDrag_proxy;
        }

        public void UpdateShadowDistance()
        {
            float diffValue = 0;
            float shadowDistance = 0;
            shadowDistance = _perLevelHeight * _curZoom * 2 + 10;
            QualitySettings.shadowDistance = shadowDistance + diffValue;
        }

        private IEnumerator DelayReset(float delay = 0.1f)
        {
            yield return new WaitForSeconds(delay);
            Input.ResetInputAxes();
        }

        private void OnZoomLevel()
        {
            _curZoom = Mathf.Clamp(_curZoom,0, MaxZoomLevel);
            float hight = Mathf.Lerp(mMinHeight, mMaxHeight, 1.0f * _curZoom / MaxZoomLevel);
            transform.DOMoveY(hight, 0.35f);
            UpdateShadowDistance();
            UpdateMoveSpeedFactor();
        }
        private void UpdateMoveSpeedFactor()
        {//更新移动屏幕比例speed
            Vector3 center = mCamera.ViewportToScreenPoint(new Vector3(0.5f, 0.5f));
            Ray ray = mCamera.ScreenPointToRay(center);
            if (Physics.Raycast(ray, out _rayHit))
            {
                center = _rayHit.point;
                Vector3 v1 = mCamera.WorldToScreenPoint(center + Vector3.left);
                Vector3 v2 = mCamera.WorldToScreenPoint(center + Vector3.right);
                _factor = Vector3.Distance(v1, v2);// * Time.deltaTime;
                _factor = 2 / _factor; // * 5;
            }
        }
        public void OnPointerDown(Vector2 pos)
        {
            _ray = mCamera.ScreenPointToRay(pos);
            if (Physics.Raycast(_ray, out _rayHit))
            {
                Vector3 hitPos = _rayHit.point;
                OnPointDown(pos, hitPos);
            }
            else
                OnPointDown(pos, nullPointer);
            _pointerDown = pos;
            _lastPointerTime = Time.time;
        }
        public void OnPointerUp(Vector2 pos)
        {
            _ray = mCamera.ScreenPointToRay(pos);
            if (Physics.Raycast(_ray, out _rayHit))
            {
                Vector3 hitPos = _rayHit.point;
                OnPointUp(pos, hitPos);
                if (Time.time - _lastPointerTime < 0.35f && Vector3.Distance(pos, _pointerDown) < 5)
                {
                    OnTap(pos, hitPos);
                }
            }
        }


        public void OnPointerMove(Vector2 pixelPosition, Vector2 delta)
        {
            if (!_zooming && _cameraOn)
            {//拖拽
                if (delta.magnitude > 1)
                {
                    Vector2 pp = _inputProvider.PointerPosition;
                    if (!OnDrag(pp))
                    {
                        delta.y = -delta.y * _factor;// * 0.2f;
                        delta.x = -delta.x * _factor;// * 0.2f;
                        Vector3 cameraPosition = _cameraTransform.localPosition;
                        cameraPosition.x += delta.x;// * Time.deltaTime;
                        cameraPosition.z += delta.y;// * Time.deltaTime;

                        //cameraPosition = CheckBounds(cameraPosition);
                        _cameraTransform.localPosition = cameraPosition;
                    }
                }
            }
        }

        public void OnPointerZoom(Vector2 pixelPosition, float dis)
        {
            if (dis != 0 && !_zoomEffecting)
            {
                if (dis > 0 && dis > _zoomFactor)// && v.y < 25.0f)
                {//缩小
                    if (_curZoom < MaxZoomLevel)
                    {
                        _curZoom++;
                        OnZoomLevel();
                        OnZoom(_curZoom);
                    }
                }
                else if (dis < 0 && dis < -_zoomFactor)// && v.y > 3.0f)
                {//放大
                    if (_curZoom > 0)
                    {
                        _curZoom--;
                        OnZoomLevel();
                        OnZoom(_curZoom);
                    }
                }
                _zooming = true;
            }
        }
        public void UpdatePointers()
        {
            if (_CameraFonze || !IsCameraOn())
            {
                if (_cameraOn)
                    _cameraOn = false;
                return;
            }
            _inputProvider.ProcessPointer();
            if (_zooming)
            {
                if (_lastZoom != _curZoom)
                {
                    _lastZoom = _curZoom;
                }
                if (!_zoomEffecting)
                {
                    _zooming = false;
                }
            }
            if (!_cameraOn)
                _cameraOn = true;
        }

        /// ***************** 编辑用 ***********
        [SerializeField]
        private Vector3 paddingEdge = new Vector3(2, 1.5f, 1);
        [SerializeField]
        private bool isDbugMinZoom = true;
        [SerializeField]
        private bool isDebugSelfUpdate = false;
        [ContextMenu("ResetZoomLevels")]
        void ResetZoomLevels()
        {
            _lastZoom = 1;
            _curZoom = isDbugMinZoom ? 0 : MaxZoomLevel;
            OnZoom(_curZoom);
            _zooming = true;
            if (isDebugSelfUpdate)
            {
                Invoke("ResetZoomLevels", 0.5f);
            }
        }
    }
}
